/* Copyright 2012 Tobias Marschall
 *
 * This file is part of CLEVER.
 *
 * CLEVER is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * CLEVER is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with CLEVER.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>

#include <boost/program_options.hpp>

#include <bamtools/api/BamReader.h>
#include <bamtools/api/BamWriter.h>

#include "VersionInfo.h"

using namespace std;
namespace po = boost::program_options;

void usage(const char* name, const po::options_description& options_desc) {
	cerr << "Usage: " << name << " [options]" << endl;
	cerr << endl;
	cerr << "Reads BAM format from stdin and outputs BAM format to stdout, where " << endl;
	cerr << "some alignments can be excluded based on option settins." << endl;
	cerr << endl;
	cerr << options_desc << endl;
	exit(1);
}


int main(int argc, char* argv[]) {
	VersionInfo::checkAndPrintVersion("filter-bam", cerr);
	string commandline = VersionInfo::commandline(argc, argv);

	// PARAMETERS
	string exclude_readgroup;

	po::options_description options_desc("Allowed options");
	options_desc.add_options()
		("exclude_readgroup", po::value<string>(&exclude_readgroup)->default_value(""), "Name of readgroup to discard.")
	;

	if (isatty(fileno(stdin)) || (argc<1)) {
		usage(argv[0], options_desc);
	}

	po::variables_map options;
	try {
		po::store(po::parse_command_line(argc, argv, options_desc), options);
		po::notify(options);
	} catch(exception& e) {
		cerr << "error: " << e.what() << "\n";
		return 1;
	}
	cerr << "Commandline: " << commandline << endl;

	BamTools::BamReader bam_reader;
	if (!bam_reader.Open("/dev/stdin")) {
		cerr << "Error opening BAM input from /dev/stdin" << endl;
		return 1;
	}
	const BamTools::RefVector& bam_ref_data = bam_reader.GetReferenceData();
	BamTools::SamHeader sam_header(bam_reader.GetHeader());
	if (exclude_readgroup.size() > 0) {
		sam_header.ReadGroups.Remove(exclude_readgroup);
	}
	BamTools::BamWriter bam_writer;
	if (!bam_writer.Open("/dev/stdout", sam_header, bam_ref_data)) {
		cerr << "Error writing BAM to stdout." << endl;
		return 1;
	}
	
	BamTools::BamAlignment aln;
	long long counter = 0;
	while ( bam_reader.GetNextAlignment(aln) ) {
		counter += 1;
		if (counter % 200000 == 0) {
			cerr << "Having processed " << counter << " read alignments" << endl;
		}
		if (exclude_readgroup.size() > 0) {
			string rg;
			if (aln.GetTag("RG", rg)) {
				if (rg.compare(exclude_readgroup) == 0) {
					continue;
				}
			}
		}
		bam_writer.SaveAlignment(aln);
	}
	bam_writer.Close();
	return 0;
}
